﻿using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Forms;
using Greg.XmlEditor.Presentation.Commands;
using Greg.XmlEditor.Presentation.Presenters;

namespace Greg.XmlEditor.Presentation.Views
{
	public partial class MasterView : Form
	{
		private readonly MasterPresenter presenter;

		public MasterView(MasterPresenter presenter)
		{
			this.presenter = presenter;
			this.InitializeComponent();
			this.presenter.PropertyChanged += OnPresenterPropertyChanged;
			this.presenter.Documents.CollectionChanged += OnDocumentsChanged;

			CommandManager.Instance.Bindings.Add(this.presenter.NewCommand, newMenu);
			CommandManager.Instance.Bindings.Add(this.presenter.NewCommand, newTool);
			CommandManager.Instance.Bindings.Add(this.presenter.OpenCommand, openMenu);
			CommandManager.Instance.Bindings.Add(this.presenter.OpenCommand, openTool);
			CommandManager.Instance.Bindings.Add(this.presenter.CloseCommand, closeMenu);
			CommandManager.Instance.Bindings.Add(this.presenter.CloseCommand, closeTool);
			CommandManager.Instance.Bindings.Add(this.presenter.CloseCommand, closeContextTool);

			CommandManager.Instance.Bindings.Add(this.presenter.OpenSchemaCommand, openSchemaContextTool);
			CommandManager.Instance.Bindings.Add(this.presenter.OpenStyleCommand, openStyleContextTool);
			CommandManager.Instance.Bindings.Add(this.presenter.ApplyStyleCommand, applyStyleContextTool);

			CommandManager.Instance.Bindings.Add(this.presenter.SaveCommand, saveMenu);
			CommandManager.Instance.Bindings.Add(this.presenter.SaveCommand, saveTool);
			CommandManager.Instance.Bindings.Add(this.presenter.SaveAsCommand, saveAsMenu);
			CommandManager.Instance.Bindings.Add(this.presenter.SaveAllCommand, saveAllMenu);
			CommandManager.Instance.Bindings.Add(this.presenter.SaveAllCommand, saveAllTool);

			CommandManager.Instance.Bindings.Add(this.presenter.ExitCommand, exitMenu);

			CommandManager.Instance.Bindings.Add(this.documentView.Editor.UndoCommand, undoMenu);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.UndoCommand, undoTool);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.RedoCommand, redoMenu);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.RedoCommand, redoTool);

			CommandManager.Instance.Bindings.Add(this.documentView.Editor.CutCommand, cutMenu);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.CutCommand, cutTool);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.CopyCommand, copyMenu);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.CopyCommand, copyTool);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.PasteCommand, pasteMenu);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.PasteCommand, pasteTool);
			CommandManager.Instance.Bindings.Add(this.documentView.Editor.FindAndReplaceCommand, findAndReplaceMenu);

			CommandManager.Instance.Bindings.Add(this.documentView.Editor.SelectAllCommand, selectAllToolStripMenuItem);

			this.UpdateChildViews();
		}

		private void OnPresenterPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			switch (e.PropertyName)
			{
				case "CurrentDocument":
					this.UpdateChildViews();
					break;
			}
		}

		private void UpdateChildViews()
		{
			if (this.presenter.CurrentDocument == null)
			{
				this.documentView.Presenter = null;
				this.documentDetailsView.Presenter = null;
				this.containerMain.Panel2Collapsed = true;
				this.Text = "Greg's XML Editor";
				return;
			}

			this.documentView.Presenter = this.presenter.CurrentDocument;

			this.Text = (string.IsNullOrEmpty(this.presenter.CurrentDocument.Name)) ?
                "[undefined] - Greg's XML Editor" :
				this.presenter.CurrentDocument.Name + " - Greg's XML Editor";


			if (this.presenter.CurrentDocument is DocumentPresenter)
			{
				this.documentDetailsView.Presenter = (DocumentPresenter)this.presenter.CurrentDocument;
			}
			else if (this.presenter.CurrentDocument is ChildDocumentPresenterBase)
			{
				this.documentDetailsView.Presenter = ((ChildDocumentPresenterBase)this.presenter.CurrentDocument).Document;
			}
			else
			{
				this.documentDetailsView.Presenter = null;
			}

			if (this.containerMain.Panel2Collapsed)
				this.containerMain.Panel2Collapsed = false;

			foreach (var document in this.presenter.Documents)
			{
				this.AddTreeNode(document);
			}
		}

		private void OnDocumentsChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			switch (e.Action)
			{
				case NotifyCollectionChangedAction.Add:
					foreach (var item in e.NewItems)
					{
						this.AddTreeNode((DocumentPresenter) item);
					}
					break;
				case NotifyCollectionChangedAction.Remove:
					foreach (var item in e.OldItems)
					{
						this.RemoveTreeNode((DocumentPresenter)item);
					}
					break;
			}
		}

		private void AddTreeNode(DocumentPresenter documentPresenter)
		{
			var node = new DocumentNodeView(documentPresenter)
           	{
           		ContextMenuStrip = this.treeContextMenu
           	};
			this.documentTree.Nodes.Add(node);
		}

		private void RemoveTreeNode(DocumentPresenter documentPresenter)
		{
			DocumentNodeView nodeToRemove = null;
			foreach (var nodeObject in this.documentTree.Nodes)
			{
				if (!(nodeObject is DocumentNodeView)) continue;
				var node = (DocumentNodeView)nodeObject;
				if (node.Presenter != documentPresenter) continue;
				nodeToRemove = node;
				break;
			}

			if (nodeToRemove == null) return;
			nodeToRemove.DetachPresenter();
			this.documentTree.Nodes.Remove(nodeToRemove);
		}

		private void OnNodeSelected(object sender, TreeViewEventArgs e)
		{
			this.presenter.CurrentDocument = e.Node.Tag as DocumentPresenterBase;
		}

		private void OnNodeClick(object sender, TreeNodeMouseClickEventArgs e)
		{
			this.presenter.CurrentDocument = e.Node.Tag as DocumentPresenterBase;
		}

		private void OnAboutClick(object sender, System.EventArgs e)
		{
			using (var dialog = new AboutBox())
			{
				dialog.ShowDialog(this);
			}
		}

		private void OnDragEnter(object sender, DragEventArgs e)
		{
			// make sure they're actually dropping files (not text or anything else)
			if (!e.Data.GetDataPresent(DataFormats.FileDrop, false)) return;

			// allow them to continue
			// (without this, the cursor stays a "NO" symbol
			e.Effect = DragDropEffects.All;
		}

		private void OnDragDrop(object sender, DragEventArgs e)
		{
			var files = (string[])e.Data.GetData(DataFormats.FileDrop);

			if (files != null && files.Length > 0)
			{
				this.presenter.Open(files[0]);
			}
		}
	}
}
